Introducción
El diseño se define como "el proceso de definición de la arquitectura, los componentes, las interfaces y otras características de un sistema o componente" y "el resultado de ese proceso".
Según Sommerville: El diseño de software es una actividad creativa donde se identifican los componentes del software y sus relaciones, con base en los requerimientos de un cliente.
Visto como un proceso, el diseño de software es la actividad del ciclo de vida de la ingeniería de software en la que se analizan los requisitos del software para producir una descripción de la estructura interna del software que servirá como base para su construcción. Un diseño de software (el resultado) describe la arquitectura del software, es decir, cómo se descompone y organiza el software en componentes, y las interfaces entre esos componentes.
El diseño de software consta de dos actividades que encajan entre el análisis de requisitos de software y la construcción de software:
El diseño de un sistema es correcto si un sistema construido de acuerdo a ese diseño satisface los requerimientos del sistema. Pero el objetivo del diseño no es encontrar el diseño correcto sino encontrar el mejor diseño posible dentro de las limitaciones impuestas (los requerimientos, el ambiente físico del sistema, el ambiente social, etc.).
Un diseño claramente debe ser:
Sin embargo, las dos cosas más importantes concernientes a los diseñadores es que el diseño sea:
Crear un diseño simple y eficiente de un sistema “grande” puede ser una tarea extremadamente compleja. Es una actividad básicamente creativa, la cual no puede reducirse a una serie de pasos a seguir; sin embargo, se pueden dar guías.
Si se logra manejar la complejidad, se reducen los costos del diseño y se reduce la posibilidad de introducir defectos durante el diseño.
En el Diseño de Software se itera hasta encontrar una solución adecuada:
En un sentido general, el diseño puede verse como una forma de resolución de problemas. Por ejemplo, el concepto de un problema perverso, un problema sin solución definitiva, es interesante en términos de comprensión de los límites del diseño.
Para comprender el papel del diseño de software, debemos ver cómo encaja en el ciclo de vida del desarrollo de software.
Se considera un proceso en dos pasos:
El resultado de estos dos procesos es un conjunto de modelos y artefactos que registran las principales decisiones que se han tomado, junto con una explicación de la justificación de cada decisión no trivial.
Al registrar la justificación, se mejora la capacidad de mantenimiento a largo plazo del producto de software.
Un principio es “una ley, doctrina o suposición integral y fundamental”.
Los principios de diseño de software son nociones clave que proporcionan la base para muchos enfoques y conceptos de diseño de software diferentes.
Los principios de diseño de software incluyen:
Abstracción
La abstracción es "una vista de un objeto que se enfoca en la información relevante para un propósito particular e ignora el resto de la información".
Permite al diseñador considerar un componente sin preocuparse por los detalles de implementación (por ej. describiendo comportamiento exterior sin describir los detalles internos).
Acoplamiento
"una medida de la interdependencia entre módulos en un programa informático"
Más acoplamiento → más díficil comprender y modificar.
Depende de cuánta información se necesita para entender un módulo, y qué tan compleja y explícita es esa información.
Cohesión
"una medida de la fuerza de asociación de los elementos dentro de un módulo"
Más cohesión → más fáciles de comprender y modificar.
Descomposición y modularización
Descomponer y modularizar significa que el software grande se divide en una serie de componentes nombrados más pequeños que tienen interfaces bien definidas que describen las interacciones de los componentes. Usualmente el objetivo es colocar diferentes funcionalidades y responsabilidades en diferentes componentes.
Un sistema se considera modular si consiste de componentes que se pueden implementar separadamente y el cambio en un componente tiene mínimos impactos en otros componentes.
Encapsulamiento y ocultación de información
Significa agrupar y empaquetar los detalles internos de una abstracción y hacer que esos detalles sean inaccesibles para las entidades externas.
Separación de interfaz e implementación
La separación de la interfaz y la implementación implica la definición de un componente especificando una interfaz pública (conocida por los clientes) que es independiente de los detalles de cómo se realiza el componente.
Suficiencia, completud y primitivismo
Lograr la suficiencia y la integridad significa garantizar que un componente de software capture todas las características importantes de una abstracción y nada más. Primitividad significa que el diseño debe basarse en patrones fáciles de implementar.
Separación de intereses
Permite enfrentarse a los distintos aspectos individuales de un problema de forma de concentrarse en cada uno por separado. Por ejemplo: según el tiempo (ciclo de vida), cualidades (correctitud y eficiencia).
Dividir y Conquistar
Dividir en piezas que pueden ser “conquistadas” por separado.
Las piezas están relacionadas. Juntas forman el sistema.
Existe comunicación y cooperación entre ellas - esto agrega complejidad, que surge de la propia partición.
Cuando el costo de particionar sumado la complejidad agregada supera los ahorros logrados por particionar se debe detener el proceso.
Reuso
Utilizar nuevamente algo (o construir pensado en).
Hay varios niveles:
Una serie de cuestiones clave deben abordarse al diseñar software. Algunas son preocupaciones de calidad que todo software debe abordar, por ejemplo, rendimiento, seguridad, confiabilidad, facilidad de uso, etc. Otro tema importante es cómo descomponer, organizar y empaquetar componentes de software.
Por el contrario, otros problemas "tratan con algún aspecto del comportamiento del software que no está en el dominio de la aplicación, pero que aborda algunos de los dominios de soporte". Estos problemas, que a menudo atraviesan la funcionalidad del sistema, se han denominado aspectos, que "tienden a no ser unidades de descomposición funcional del software, sino más bien propiedades que afectan el rendimiento o la semántica de los componentes de manera sistémica".
En sentido estricto, una arquitectura de software es “el conjunto de estructuras necesarias para razonar sobre el sistema, que comprende los elementos del software, las relaciones entre ellos y las propiedades de ambos”.
Se pueden describir y documentar diferentes facetas de alto nivel de un diseño de software. Estas facetas a menudo se denominan vistas: "Una vista representa un aspecto parcial de una arquitectura de software que muestra propiedades específicas de un sistema de software".
Un estilo arquitectónico es “una especialización de elementos y tipos de relaciones, junto con un conjunto de restricciones sobre cómo se pueden usar”.
Por lo tanto, se puede considerar que un estilo arquitectónico proporciona la organización de alto nivel del software. Varios autores han identificado una serie de estilos arquitectónicos importantes:
• Estructuras generales (por ejemplo, capas, tuberías y filtros, pizarra)
• Sistemas distribuidos (por ejemplo, servidor de cliente, tres niveles, intermediario)
• Sistemas interactivos (por ejemplo, Model-ViewController, resentation-Abstraction-Control)
• Sistemas adaptables (por ejemplo, microkernel, reflexión)
• Otros (por ejemplo, lotes, intérpretes, control de procesos, basados en reglas).
Un patrón es “una solución común a un problema común en un contexto dado”.
Los patrones de diseño se pueden utilizar para describir detalles en un nivel inferior. Estos patrones de diseño de nivel inferior incluyen lo siguiente:
• Patrones de creación (por ejemplo, builder, factory, prototype, singleton)
• Patrones estructurales (por ejemplo, adapter, bridge, composite, decorator, façade, flyweight, proxy)
• Patrones de comportamiento (por ejemplo, command, interpreter, iterator, mediator, memento, observer, state, strategy, template, visitor)
El diseño arquitectónico es un proceso creativo. Durante el proceso de diseño, los diseñadores de software tienen que tomar una serie de decisiones fundamentales que afectan profundamente al software y al proceso de desarrollo.
Un enfoque para permitir la reutilización de diseños y componentes de software es diseñar familias de programas, también conocidas como líneas de productos de software.
Un framework: un sistema de software parcialmente completado que se puede ampliar mediante la instanciación adecuada de extensiones específicas.